package org.apache.skywalking.apm.plugin.kepler;

import com.xiaomaoguai.fcp.pre.kepler.common.constants.KeplerCommonConstant;
import com.xiaomaoguai.fcp.pre.kepler.common.utils.JsonUtils;
import com.xiaomaoguai.fcp.pre.kepler.router.buf.Buf;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.handlercontext.TailContext;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.StringTag;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.plugin.kepler.utils.WrapperDiffUtils;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * @author WeiHui-Z
 * @version v1.0.0
 * @date 2019/6/5 17:22
 * @since JDK 1.8
 */
public class KeplerStandardTailHandlerInterceptor implements InstanceMethodsAroundInterceptor {

	@Override
	public void beforeMethod(EnhancedInstance enhancedInstance, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult methodInterceptResult) throws Throwable {
		final TailContext tailContext = (TailContext) allArguments[0];
		final Buf buf = tailContext.getBuf();
		final String productCode = (String) buf.get(KeplerCommonConstant.PRODUCT_CODE);
		final String routerName = tailContext.getRouter().getRouterName();
		final Map<String, Object> context = tailContext.getBuf().getContext();

		AbstractSpan activeSpan = ContextManager.createLocalSpan("End=>" + routerName + ".RouterOut");
		activeSpan.tag(new StringTag("routerName"), routerName);
		activeSpan.tag(new StringTag("productCode"), productCode);
		activeSpan.tag(new StringTag("beforeRouterOut"), JsonUtils.toFormatJsonString(context));
	}

	@Override
	public Object afterMethod(EnhancedInstance enhancedInstance, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object o) throws Throwable {
		final TailContext tailContext = (TailContext) allArguments[0];
		final Object context = tailContext.getOutParam();

		final String afterJson = JsonUtils.toFormatJsonString(context);
		final String beforeJson = (String) ContextManager.getRuntimeContext().get(Constants.CONVERT_VALUE);
		final String diff = WrapperDiffUtils.getDiff(afterJson, beforeJson);

		AbstractSpan activeSpan = ContextManager.activeSpan();
		activeSpan.tag(new StringTag("afterRouterOut"), afterJson);
		activeSpan.tag(new StringTag("diff"), diff);
		ContextManager.stopSpan();
		return o;
	}

	@Override
	public void handleMethodException(EnhancedInstance enhancedInstance, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable throwable) {
		ContextManager.activeSpan().errorOccurred().log(throwable);
	}

}
